(*lexer*)

{ (*header*)
open Grammar
open String
}

let real	= (['0'-'9']*'.'['0'-'9']+)|(['0'-'9']+'.')		(*real numbers*)
let ints	= ['0'-'9']+						(*integers*)
let type_annot	= ['A'-'Z']['a'-'z' 'A'-'Z' '0'-'9' '_']*		(*type annotations*)
let identifier	= ['a'-'z' '_']['a'-'z' 'A'-'Z' '0'-'9' '_']*'\''*	(*identifiers*)
let wspace	= [' ' '\t' '\n' '\r']+					(*white space, including newlines*)
let chr		= '\''[^'\'']'\''					(*characters*)	
let strng	= '\"'[^'\"']*'\"'					(*strings*)

rule entry = parse
	  eof			{EOF}					(*end of file*)
	| "\n"                  {Lexing.new_line lexbuf; entry lexbuf}
	| "//"			{comment_line lexbuf}			(*parse comments*)
	| "/*"			{comment_block lexbuf}			
	| ";"			{SEMICOLON}				(*end of statement*)
	| real as rnum		{REAL(float_of_string rnum)}		(*numbers*)
	| ints as inum		{INT(int_of_string inum)}		(*integers*)
	| "#t"			{BOOL(true)}				(*booleans*)
	| "#f"			{BOOL(false)}			
	| strng as sval		{STRING(sub sval 1 (length sval - 2))}	(*strings*)
	| chr as cval		{CHAR(cval.[1])}			(*characters*)
	| "if"			{IF}					(*conditional keywords*)
	| "if*"                 {IFD}
	| "then"		{THEN}					
	| "else"		{ELSE}
	| "/if*"                {ENDIF}
	| "/if"	        	{ENDIF}
	| "match"		{MATCH}
	| "match*"              {MATCHD}
	| "with"		{MWITH}
	| "/match*"		{ENDMATCH}
	| "/match"		{ENDMATCH}
	| "nil"			{NIL}
	| "NIL"			{NIL}
	| "[]"			{NIL}	
	| "->"			{TO}	
	| "::"			{ATTACH}
	| "=>"			{WITH}
	| ":"			{COLON}				
	| "using"		{USING}
	| "Dyn"			{DYNAMIC}				(*types*)
	| "Dynamic"		{DYNAMIC}
	| "String"		{STRING_TYPE}
	| type_annot as tau	{TYPE(tau)}				
	| "'"			{TICK}
	| identifier as id	{ID(id)}				(*identifiers*)
	| "$$"                  {PREV}
	| ":="			{GETS}					(*let*)
	| ","			{COMMA}
	| "<-"			{HAS}					(*permanent let*)
	| "*"			{MULT}					(*numerical operators*)
	| "/"			{DIV}
	| "+"			{ADD}
	| "-"			{SUB}
	| "%"			{MOD}
	| "^"			{EXP}
	| "!"			{EXCLAM}
	| "<>"			{NEQUAL}				(*boolean operators*)
	| "<="			{LE}
	| ">="			{GE}
	| "="			{EQUAL}
	| ">"			{GT}
	| "<"			{LT}
	| "&&"			{AND}
	| "||"			{OR}
	| "|"			{DO}
	| "&"			{LAND}
	| "("			{LPAREN}				(*left parenthesis*)
	| ")"			{RPAREN}				(*right parenthesis*)
	| "["			{LBRACK}				(*left bracket*)
	| "]"			{RBRACK}				(*right bracket*)
	| _ 			{entry lexbuf}				(*if none of the above, skip character*)
and comment_line = parse
	  eof			{EOF}
	| "\n"			{Lexing.new_line lexbuf; entry lexbuf}
	| _			{comment_line lexbuf}
and comment_block = parse
	  eof			{EOF}
	| "*/"			{entry lexbuf}
	| "\n"                  {Lexing.new_line lexbuf; comment_block lexbuf}
	| _			{comment_block lexbuf}
	
{ (*footer*)

}
